//
// Created by grant on 9/20/18.
//

#include "http_linux.h"

#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>


#define BUFFER_SIZE 1024


typedef struct TCPClient{
    int socket;
    int remote_port;
    char remote_ip[16];
    struct sockaddr_in _addr;
    int connected;
} TCPClient;


//********Http Header Settings begin**********//
char *Accept=" */*";
char *AcceptRanges=NULL;
char *Ranges=NULL;
char *Authorization=NULL;
char *ProxyAuthorization=NULL;
char *CacheControl=" no-cache";
char *Cookie=NULL;
char *ContentType=" application/x-www-form-urlencoded";
char *UserAgent="Grant Http 1.0";
//********Http Header Settings end**********//




/*根据服务器IP或者域名，以及端口填充tcpclient结构，主要是申请个socket及填一下sockaddr_in*/
int client_create(TCPClient *,const char *host, int port);
/*连接到远程端口，并修改client的连接状态*/
int client_connect(TCPClient *);
/*接收远程指定字节数的数据，并分配空间到buff，如果size为0，就阻塞直到连接关闭*/
int client_recv(TCPClient *,char **buff,int size);
/*发送buf，size为buf长度*/
int client_send(TCPClient *,char *buff,int size);
/*关闭socket并且设置连接状态*/
int client_close(TCPClient *);

int http_request(char *ip,int port,char *uri,char *params,char **response, char *method);

int client_create(TCPClient *pclient,const char *host, int port){
    struct hostent *he;

    if(pclient == NULL) return -1;
    memset(pclient,0,sizeof(TCPClient));

    if((he = gethostbyname(host))==NULL){
        return -2;
    }

    pclient->remote_port = port;
    strcpy(pclient->remote_ip,inet_ntoa( *((struct in_addr *)he->h_addr) ));

    pclient->_addr.sin_family = AF_INET;
    pclient->_addr.sin_port = htons(pclient->remote_port);
    pclient->_addr.sin_addr = *((struct in_addr *)he->h_addr);

    if((pclient->socket = socket(AF_INET,SOCK_STREAM,0))==-1){
        return -3;
    }

    /*TODO:是否应该释放内存呢?*/

    return 0;
}

int client_connect(TCPClient *pclient){
    if(pclient->connected)
        return 1;

    if(connect(pclient->socket, (struct sockaddr *)&pclient->_addr,sizeof(struct sockaddr))==-1){
        return -1;
    }

    pclient->connected = 1;

    return 1;
}

int client_recv(TCPClient *pclient,char **lpbuff,int size){
    int recvnum=0,tmpres=0;
    char buff[BUFFER_SIZE];

    *lpbuff = NULL;

    while(recvnum < size || size==0){
        tmpres = recv(pclient->socket, buff,BUFFER_SIZE,0);
        if(tmpres <= 0)
            break;
        recvnum += tmpres;

        if(*lpbuff == NULL){
            *lpbuff = (char*)malloc(recvnum);
            if(*lpbuff == NULL)
                return -2;
        }else{
            *lpbuff = (char*)realloc(*lpbuff,recvnum);
            if(*lpbuff == NULL)
                return -2;
        }

        memcpy(*lpbuff+recvnum-tmpres,buff,tmpres);
    }

    return recvnum;
}

int client_send(TCPClient *pclient,char *buff,int size){
    int sent=0,tmpres=0;

    while(sent < size){
        tmpres = send(pclient->socket,buff+sent,size-sent,0);
        if(tmpres == -1){
            return -1;
        }
        sent += tmpres;
    }
    return sent;
}

int client_close(TCPClient *pclient){
    shutdown(pclient->socket,SHUT_RDWR);
    pclient->connected = 0;
}


int http_get(char *ip,int port,char *uri,char **response)
{

    return http_request(ip,port,uri,"",response,"GET");

}

int http_post(char *ip,int port,char *uri,char *params,char **response)
{

    return http_request(ip,port,uri,params,response,"POST");

}


int http_request(char *ip,int port,char *uri,char *params,char **response, char *method)
{

    TCPClient client;
    int ret;

    //char *response = NULL;
    printf("开始组包\n");

    //创建连接客户端
    ret = client_create(&client,ip,port);

    if (ret != 0){
        printf("创建客户端失败\n");
        return -1;
    }

    char methods[300],host[100],content_len[255],header[512];
    char *lpbuf,*ptmp;
    int len=0;

    lpbuf = NULL;
    //const char *header2="User-Agent: Grant Http 0.1\r\nCache-Control: no-cache\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept: */*\r\n";

    //组织header
    if (UserAgent == NULL || strlen(UserAgent) == 0){
        UserAgent = "Grant Http 1.0";
    }
    strcat(header,"User-Agent:");
    strcat(header,UserAgent);

    if (CacheControl == NULL || strlen(CacheControl) == 0){
        CacheControl = " no-cache";
    }
    strcat(header,"\r\nCache-Control:");
    strcat(header,CacheControl);

    if (ContentType == NULL || strlen(ContentType) == 0){
        ContentType = " application/x-www-form-urlencoded";
    }
    strcat(header,"\r\nContent-Type:");
    strcat(header,ContentType);

    if (Accept == NULL || strlen(Accept) == 0){
        Accept = " */*";
    }
    strcat(header,"\r\nAccept:");
    strcat(header,Accept);

    if (AcceptRanges != NULL && strlen(AcceptRanges)>6 ){
        strcat(header,"\r\nAccept-Ranges:");
        strcat(header,AcceptRanges);
    }

    if (Ranges != NULL && strlen(Ranges)>6 ){
        strcat(header,"\r\nRanges:");
        strcat(header,Ranges);
    }

    if (Authorization != NULL && strlen(Authorization)>0){
        strcat(header,"\r\nAuthorization:");
        strcat(header,Authorization);
    }

    if (ProxyAuthorization != NULL && strlen(ProxyAuthorization)>0){
        strcat(header,"\r\nProxy-Authorization:");
        strcat(header,ProxyAuthorization);
    }

    if (Cookie != NULL && strlen(Cookie)>0){
        strcat(header,"\r\nCookie:");
        strcat(header,Cookie);
    }

    strcat(header,"\r\n");

    //组织服务器地址
    sprintf(host,"HOST: %s:%d\r\n",client.remote_ip,client.remote_port);

    //组织请求路径
    sprintf(methods,"%s %s HTTP/1.0\r\n",method,uri);

    sprintf(content_len,"Content-Length: %d\r\n\r\n",strlen(params));

    len = strlen(methods)+strlen(host)+strlen(header)+strlen(content_len)+strlen(params)+1;
    lpbuf = (char*)malloc(len);
    if(lpbuf==NULL){
        printf("创建数据失败\n");
        return -2;
    }

    strcpy(lpbuf,methods);

    strcat(lpbuf,host);
    strcat(lpbuf,header);
    strcat(lpbuf,content_len);
    strcat(lpbuf,params);

    //未连接
    if(!client.connected){
        if(client_connect(&client)!=1)
        {
            //连接不成功
            printf("连接失败\n");
            return -3;
        }
    }

    //发送请求
    if(client_send(&client,lpbuf,len)<0){
        printf("发送请求失败\n");
        return -1;
    }
    printf("发送请求:\n%s\n",lpbuf);

    /*释放内存*/
    if(lpbuf != NULL) free(lpbuf);
    lpbuf = NULL;

    /*it's time to recv from server*/
    if(client_recv(&client,&lpbuf,0) <= 0){
        printf("未接收到响应\n");
        if(lpbuf) free(lpbuf);
        return -2;
    }
    printf("接收响应:\n%s\n",lpbuf);

    /*响应代码,|HTTP/1.0 200 OK|
     *从第10个字符开始,第3位
     * */
    memset(methods,0,sizeof(methods));
    strncpy(methods,lpbuf+9,3);
    if(atoi(methods)!=200){
        if(lpbuf) free(lpbuf);
        return atoi(methods);
    }


    ptmp = (char*)strstr(lpbuf,"\r\n\r\n");
    if(ptmp == NULL){
        free(lpbuf);
        return -3;
    }
    ptmp += 4;/*跳过\r\n*/

    len = strlen(ptmp)+1;
    *response=(char*)malloc(len);
    if(*response == NULL){
        if(lpbuf) free(lpbuf);
        return -1;
    }
    memset(*response,0,len);
    memcpy(*response,ptmp,len-1);

    /*从头域找到内容长度,如果没有找到则不处理*/
    ptmp = (char*)strstr(lpbuf,"Content-Length:");
    if(ptmp != NULL){
        char *ptmp2;
        ptmp += 15;
        ptmp2 = (char*)strstr(ptmp,"\r\n");
        if(ptmp2 != NULL){
            memset(methods,0,sizeof(methods));
            strncpy(methods,ptmp,ptmp2-ptmp);
            if(atoi(methods)<len)
                (*response)[atoi(methods)] = '\0';
        }
    }

    if(lpbuf) free(lpbuf);

    return 0;

}

//********Http Header Settings begin**********//
void setAccept(char *accept)
{
    Accept = accept;
}
void setAcceptRanges(char *ranges)
{
    AcceptRanges = ranges;
}
void setAuthorization(char *authorization)
{
    Authorization = authorization;
}
void setCacheControl(char *cacheControl)
{
    CacheControl = cacheControl;
}
void setCookie(char *cookie)
{
    Cookie = cookie;
}
void setContentType(char *contentType)
{
    ContentType = contentType;
}
void setProxyAuthorization(char *proxyAuthorization)
{
    ProxyAuthorization = proxyAuthorization;
}
void setRange(char *ranges)
{
    Ranges = ranges;
}
void setUserAgent(char *userAgent)
{
    UserAgent = userAgent;
}

//********Http Header Settings end**********//


